package com.jerei.plugin.control;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jerei.plugin.entity.ActivitEntity;
import com.jerei.utils.UtilsDate;
import com.jerei.utils.spring.ApplicationContextUtils;
import com.jerei.web.plugin.controller.PluginController;
import com.jerei.web.utils.UtilsUI;
import com.jerei.web.utils.UtilsWeb;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import ro.fortsoft.pf4j.Extension;

import java.io.IOException;
import java.util.List;

/**
 * Created by sunfeihu on 2016/12/3.
 */
@Extension
public class AMControl extends PluginController {

    @RequiresPermissions("activiti-modeler:view")
    public void modeler() {
        this.getModel().addAttribute("modelId", UtilsWeb.getString(this.getRequest(), "modelId"));
    }


    @RequiresPermissions("activiti-modeler:view")
    public String page() {
        RepositoryService repositoryService = ApplicationContextUtils.get().getBean(RepositoryService.class);
        List<Model> models = repositoryService.createModelQuery().list();
        JSONArray jsonArray = new JSONArray();
        JSONObject obj = new JSONObject();
        if (null != models && models.size() > 0) {
            JSONObject _obj = null;
            for (Model model : models) {
                _obj = new JSONObject();
                _obj.put("id", model.getId());
                _obj.put("name", model.getName());
                _obj.put("key", model.getKey());
                _obj.put("category", model.getCategory());
                _obj.put("version", model.getVersion());
                _obj.put("createTime", UtilsDate.fmtDate("yyyy-MM-dd HH:mm:ss", model.getCreateTime()));
                _obj.put("lastUpdateTime", UtilsDate.fmtDate("yyyy-MM-dd HH:mm:ss", model.getLastUpdateTime()));
                _obj.put("deploymentId", model.getDeploymentId());
                jsonArray.add(_obj);
            }
        }
        obj.put("total", jsonArray.size());
        obj.put("rows", jsonArray);
        return obj.toJSONString();
    }

    @RequiresPermissions({"activiti-modeler:save", "activiti-modeler:update"})
    public void edit() {
        this.getModel().addAttribute("obj", new ActivitEntity());
    }

    @RequiresPermissions({"activiti-modeler:save", "activiti-modeler:update"})
    public String save() {
        RepositoryService repositoryService = ApplicationContextUtils.get().getBean(RepositoryService.class);
        ActivitEntity activitEntity = this.wrapper(ActivitEntity.class);
        Model modelData = null;
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            ObjectNode editorNode = objectMapper.createObjectNode();
            editorNode.put("id", "canvas");
            editorNode.put("resourceId", "canvas");
            ObjectNode stencilSetNode = objectMapper.createObjectNode();
            stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
            editorNode.put("stencilset", stencilSetNode);
            modelData = repositoryService.newModel();
            ObjectNode modelObjectNode = objectMapper.createObjectNode();
            modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, activitEntity.getName());
            modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
            activitEntity.setDescription(StringUtils.defaultString(activitEntity.getDescription()));
            modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, activitEntity.getDescription());
            modelData.setMetaInfo(modelObjectNode.toString());
            modelData.setName(activitEntity.getName());
            modelData.setKey(StringUtils.defaultString(activitEntity.getKey()));
            repositoryService.saveModel(modelData);
            repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes("utf-8"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return UtilsUI.ok();
    }

    @RequiresPermissions("activiti-modeler:view")
    public String deploy() throws IOException {
        RepositoryService repositoryService = ApplicationContextUtils.get().getBean(RepositoryService.class);
        String modelId = UtilsWeb.getString(this.getRequest(), "modelId");
        Model modelData = repositoryService.getModel(modelId);
        ObjectNode modelNode = (ObjectNode) new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));
        byte[] bpmnBytes = null;
        BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
        bpmnBytes = new BpmnXMLConverter().convertToXML(model);
        String processName = modelData.getName() + ".bpmn20.xml";
        repositoryService.createDeployment().name(modelData.getName()).addString(processName, new String(bpmnBytes)).deploy();
        return UtilsUI.ok();
    }

    @RequiresPermissions("activiti-modeler:view")
    public ResponseEntity<byte[]> export() throws IOException {
        RepositoryService repositoryService = ApplicationContextUtils.get().getBean(RepositoryService.class);
        String modelId = UtilsWeb.getString(this.getRequest(), "modelId");
        String type = UtilsWeb.getString(this.getRequest(), "type");
        Model modelData = repositoryService.getModel(modelId);
        BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
        byte[] modelEditorSource = repositoryService.getModelEditorSource(modelData.getId());
        JsonNode editorNode = new ObjectMapper().readTree(modelEditorSource);
        BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editorNode);
        if (bpmnModel.getMainProcess() == null) {
            this.getModel().addAttribute("tip", "no main process, can't export for type: " + type);
            return null;
        }
        String filename = "";
        byte[] exportBytes = null;
        String mainProcessId = bpmnModel.getMainProcess().getId();
        if (type.equals("bpmn")) {
            BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
            exportBytes = xmlConverter.convertToXML(bpmnModel);
            filename = mainProcessId + ".bpmn20.xml";
        } else if (type.equals("json")) {
            exportBytes = modelEditorSource;
            filename = mainProcessId + ".json";
        }
        HttpHeaders headers = new HttpHeaders();
        headers.setContentDispositionFormData("attachment", filename);
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        return new ResponseEntity<byte[]>(exportBytes, headers, HttpStatus.CREATED);
    }

    @RequiresPermissions("activiti-modeler:remove")
    public String delete() {
        RepositoryService repositoryService = ApplicationContextUtils.get().getBean(RepositoryService.class);
        String[] ids = this.getRequest().getParameterValues("ids");
        if (null != ids && ids.length > 0) {
            for (String id : ids) {
                repositoryService.deleteModel(id);
            }
        }
        return UtilsUI.ok();
    }

    @RequiresPermissions("activiti-modeler:view")
    public String deploysPage() {
        RepositoryService repositoryService = ApplicationContextUtils.get().getBean(RepositoryService.class);
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();
        if (null != list && list.size() > 0) {
            JSONObject rs = new JSONObject();
            rs.put("total", list.size());
            JSONArray array = new JSONArray();
            JSONObject obj = null;
            for (ProcessDefinition pd : list) {
                obj = new JSONObject();
                obj.put("id", pd.getId());
                obj.put("category", pd.getCategory());
                obj.put("name", pd.getName());
                obj.put("key", pd.getKey());
                obj.put("description", pd.getDescription());
                obj.put("version", pd.getVersion());
                obj.put("deploymentId", pd.getDeploymentId());
                obj.put("diagramResourceName", pd.getDiagramResourceName());
                obj.put("tenantId", pd.getTenantId());
                obj.put("hasStartFormKey", pd.hasStartFormKey());
                obj.put("hasGraphicalNotation", pd.hasGraphicalNotation());
                obj.put("isSuspended", pd.isSuspended());
                array.add(obj);
            }
            rs.put("rows", array);
            return rs.toJSONString();
        }
        return UtilsUI.datagrid();
    }

}